package com.miniserver.util;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.sql.Types;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;
import java.util.StringTokenizer;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathFactory;

import net.sf.json.JSONArray;
import net.sf.json.JSONObject;

import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.http.HttpException;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.impl.HttpSolrServer;
import org.apache.solr.client.solrj.response.QueryResponse;
import org.apache.solr.common.SolrDocument;
import org.apache.solr.common.SolrDocumentList;
import org.apache.solr.common.SolrInputDocument;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import com.miniserver.tql.TqlGlobal;
import com.miniserver.tql.database.EngineContext;
import com.miniserver.tql.database.model.TNode;

/**
 * 同步内存数据库数据到Solr中，查询Solr 使用GetInstance()获取实例
 * 
 * @author zzlt104
 * 
 */
public class SolrUtil {
	private static LogUtil log = LogUtil.getLogUtil("SolrUtil");
	private static int fetchSize = 1000;
	private Document config = null;
	private long lastUpdateTime = 0;
	private HttpSolrServer solrServer;
	private HashMap<Long, String> categoryDataMap = new HashMap<Long, String>();

	private SolrUtil() {
		DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
		File backFile = null;
		try {
			File xmlFile = new File(System.getProperty(AppConfiguration.getWebRootName()),
					"WEB-INF/data/solr_config.xmlbin");
			if (xmlFile.exists()) {
				backFile = new File(System.getProperty(AppConfiguration.getWebRootName()),
						"WEB-INF/data/solr_config.xmlbin1");
				DocumentBuilder builder = factory.newDocumentBuilder();
				DKeyDesEncrypt.decryptFile(xmlFile, backFile);
				config = builder.parse(backFile);
				config.normalize();
				solrServer = new HttpSolrServer(getConfigStringValue(config, "//solrServerUrl"));
				solrServer.setSoTimeout(30 * 1000); // socket read timeout
				solrServer.setConnectionTimeout(30 * 1000);
				solrServer.setDefaultMaxConnectionsPerHost(100);
				solrServer.setMaxTotalConnections(100);
				solrServer.setFollowRedirects(false); // defaults to false
				solrServer.setMaxRetries(1); // defaults to 0. > 1 not
												// recommended.
			}
		} catch (Exception ex) {
			log.error("Solr连接初始化失败", ex);
		} finally {
			if (backFile != null) {
				backFile.delete();
			}
		}
	}

	/**
	 * 获取配置项
	 * 
	 * @param key
	 *            配置项名称，使用XPath搜索
	 * @return 返回对应的配置项
	 */
	private String getConfigStringValue(Node node, String key) {
		XPathFactory pathFactory = XPathFactory.newInstance();
		XPath xpath = pathFactory.newXPath();
		try {
			XPathExpression pathExpression = xpath.compile(key);
			Object result = pathExpression.evaluate(node, XPathConstants.NODESET);
			NodeList nodes = (NodeList) result;
			if (nodes.getLength() == 1) {
				Node val = nodes.item(0);
				if (val.hasChildNodes()) {
					return val.getFirstChild().getNodeValue();
				} else {
					return val.getNodeValue();
				}
			}
		} catch (Exception ex) {
			log.error("配置文件读取失败", ex);
		}
		return "";
	}

	static SolrUtil solrInstance = new SolrUtil();

	public static SolrUtil getInstance() {
		return solrInstance;
	}

	/**
	 * 清空Solr或者对应的表
	 * 
	 * @param tableName
	 *            表名
	 * @throws SolrServerException
	 * @throws IOException
	 */
	private boolean clearSolr(String tableName) {
		try {
			if (tableName == null) {
				solrServer.deleteByQuery("*:*");
			} else {
				solrServer.deleteByQuery("table_name:" + tableName);
			}
			solrServer.commit();
		} catch (Exception ex) {
			log.error("清除Solr数据失败");
		}
		return true;
	}

	/**
	 * 同步数据到Solr中
	 * 
	 * @return
	 */
	public boolean synchroData() {
		XPathFactory pathFactory = XPathFactory.newInstance();
		XPath xpath = pathFactory.newXPath();
		try {
			if (config == null) {
				return true;
			}
			XPathExpression pathExpression = xpath.compile("//config/synDataConfig/item");
			Object result = pathExpression.evaluate(config, XPathConstants.NODESET);
			NodeList nodes = (NodeList) result;
			int nodeSize = nodes.getLength();
			Node childItem = null;
			String tableName = null;
			String querySql = null;
			String idCol = null;
			String statusCol = null;
			String modifyCol = null;
			String copyFields = null;
			String dbName = null;
			boolean isSuccess = true;
			for (int i = 0; i < nodeSize; i++) {
				isSuccess = true;
				childItem = nodes.item(i);
				tableName = getConfigStringValue(childItem, "./tableName").toLowerCase();
				querySql = getConfigStringValue(childItem, "./querySql").toLowerCase();
				idCol = getConfigStringValue(childItem, "./idCol").toLowerCase();
				statusCol = getConfigStringValue(childItem, "./statusCol").toLowerCase();
				modifyCol = getConfigStringValue(childItem, "./modifyCol").toLowerCase();
				copyFields = getConfigStringValue(childItem, "./copyFields").toLowerCase();
				dbName = getConfigStringValue(childItem, "./dbName");
				boolean isNeedCategoryCast = false;
				if (getConfigStringValue(childItem, "./categoryChange").equalsIgnoreCase("1")) {
					isNeedCategoryCast = true;
				}
				lastUpdateTime = 0;
				isSuccess = deleteSolrRecord(dbName, tableName, idCol, modifyCol);
				if (isSuccess)
					isSuccess = addSolrRecord(dbName, tableName, querySql, statusCol, modifyCol, copyFields,
							isNeedCategoryCast) > 0;
				if (isSuccess && lastUpdateTime > 0)
					saveTimestamp(String.format("%s_%s", dbName, tableName), this.lastUpdateTime);
			}
		} catch (Exception ex) {
			log.error("同步Solr数据失败");
		}
		return false;
	}

	/**
	 * 删除指定表对应id的记录
	 * 
	 * @param tableName
	 *            表名
	 * @param id
	 *            唯一键列表
	 * @throws SolrServerException
	 * @throws IOException
	 */
	private boolean deleteSolrRecord(String dbName, String tableName, String keyFieldName, String modifyFieldName) {
		Connection conn = null;
		ResultSet resultSet = null;
		try {
			String solrTableName = String.format("%s_%s", dbName, tableName);
			long stamp = getTimestamp(solrTableName);
			if (stamp == 0L) {
				clearSolr(solrTableName);
				return true;
			}
			StringBuffer querySqlBuffer = new StringBuffer();
			querySqlBuffer.append("select ").append(keyFieldName);
			querySqlBuffer.append(" from ").append(tableName);
			querySqlBuffer.append(" where ").append(modifyFieldName).append(">?");
			conn = TqlGlobal.getTqlMaster().getPhysicalPool(dbName).getConnection();
			PreparedStatement statement = conn.prepareStatement(querySqlBuffer.toString());
			statement.setTimestamp(1, new Timestamp(stamp));
			resultSet = statement.executeQuery();
			ArrayList<Long> idList = new ArrayList<Long>();
			while (resultSet.next()) {
				idList.add(resultSet.getLong(1));
			}
			if (resultSet != null) {
				resultSet.close();
				resultSet = null;
			}
			if (conn != null) {
				conn.close();
				conn = null;
			}
			if (idList.size() < 1)
				return true;
			StringBuffer deleteBuffer = new StringBuffer();
			tableName = tableName.toLowerCase();
			deleteBuffer.append("table_name:").append(solrTableName);
			deleteBuffer.append(" AND ( ");
			int size = deleteBuffer.length();
			for (Long key : idList) {
				deleteBuffer.append(tableName).append("_").append(keyFieldName);
				deleteBuffer.append(":").append(key).append(" OR ");
				if (deleteBuffer.length() > 2048) {
					deleteBuffer.setLength(deleteBuffer.length() - 3);
					deleteBuffer.append(")");
					solrServer.deleteByQuery(deleteBuffer.toString());
					solrServer.commit();
					deleteBuffer.setLength(0);
					deleteBuffer.append("table_name:").append(solrTableName);
					deleteBuffer.append(" AND ( ");
				}
			}
			if (deleteBuffer.length() > size) {
				deleteBuffer.setLength(deleteBuffer.length() - 3);
				deleteBuffer.append(")");
				solrServer.deleteByQuery(deleteBuffer.toString());
				solrServer.commit();
				deleteBuffer.setLength(0);
			}
			return true;
		} catch (Exception ex) {
			log.error("删除已存在Solr数据失败");
		} finally {
			if (resultSet != null) {
				try {
					resultSet.close();
				} catch (SQLException e) {
				}
				resultSet = null;
			}
			if (conn != null) {
				try {
					conn.close();
				} catch (SQLException e) {
				}
			}
		}
		return false;
	}

	/**
	 * 批量添加记录到Solr中 如果Solr中不存在对应的字段或者copy field，将使用表名+"_"+字段名添加到Solr中
	 * 
	 * 
	 * @param tableName
	 *            表名
	 * @param isNeedCategoryCast
	 * @param rs
	 *            sql结果集
	 * @return
	 * @throws SQLException
	 * @throws SolrServerException
	 * @throws IOException
	 */
	private long addSolrRecord(String dbName, String tableName, String querySql, String statusFieldName,
			String modifyFieldName, String copyFields, boolean isNeedCategoryCast) {
		long count = 0;
		int innerCount = 0;
		String solrTableName = String.format("%s_%s", dbName, tableName);
		long stamp = getTimestamp(solrTableName);
		this.lastUpdateTime = stamp;
		Collection<SolrInputDocument> docs = new ArrayList<SolrInputDocument>();
		StringBuffer buffer = new StringBuffer(querySql);
		/*
		 * <categoryChange>1</categoryChange>
		 * <categoryField>category</categoryField>
		 * <categoryTable>t_pm_product_category</categoryTable>
		 * <categorySearchSql>select id,name from t_pm_product_category where
		 * store_id=?</categorySearchSql> <storeidField>store_id</storeidField>
		 */
		// 只添加status=1的数据
		if (StringUtils.isNotBlank(statusFieldName)) {
			if (querySql.indexOf(" where ") < 0) {
				buffer.append(" where ");
			} else {
				buffer.append(" and ");
			}
			buffer.append(statusFieldName).append(" =1 ");
			if (stamp > 0) {
				buffer.append(" and ").append(modifyFieldName).append(" > ?");
			}
		} else {
			if (stamp > 0) {
				buffer.append(" where ").append(modifyFieldName).append(" > ?");
			}
		}
		Connection conn = null;
		ResultSet resultSet = null;
		PreparedStatement statement = null;
		try {
			conn = TqlGlobal.getTqlMaster().getPhysicalPool(dbName).getConnection();
			statement = conn.prepareStatement(buffer.toString());
			if (stamp > 0) {
				statement.setTimestamp(1, new Timestamp(stamp));
			}
			resultSet = statement.executeQuery();
			ResultSetMetaData rsm = resultSet.getMetaData();
			int categoryIndex = -1;
			String[] colNames = null;
			StringBuilder idBuffer = new StringBuilder();
			int numColumns = 0;
			while (resultSet.next()) {
				if (count == 0) {
					colNames = checkSolrFields(rsm, tableName, copyFields);
					numColumns = colNames.length;
					if (isNeedCategoryCast) {
						categoryIndex = initCategoryData(rsm, dbName);
						if (categoryIndex < 0)
							isNeedCategoryCast = false;
					}
				}
				lastUpdateTime = Math.max(resultSet.getTimestamp(modifyFieldName).getTime(), lastUpdateTime);
				count++;
				innerCount++;
				idBuffer.setLength(0);
				SolrInputDocument doc = new SolrInputDocument();
				doc.addField("table_name", solrTableName);
				doc.addField("loadtime", new Date());
				for (int j = 1; j < numColumns; j++) {
					if (colNames[j] != null) {
						Object f = resultSet.getObject(j);
						idBuffer.append(f);
						if (isNeedCategoryCast && j == categoryIndex) {
							try {
								String category = (String) f;
								String value = "";
								String[] items = category.split(",");
								int index = -1;
								for (String item : items) {
									if (categoryDataMap.containsKey(Long.valueOf(item))) {
										if (index > -1) {
											value = value.concat(",");
										}
										index = 0;
										value = value.concat(categoryDataMap.get(Long.valueOf(item)));
									}
								}
								if (index > -1)
									f = value;
							} catch (Exception ex) {
								// System.out.println(ex);
							}
						}
						doc.addField(colNames[j], f);
					}
				}
				doc.addField("id", String.valueOf(HashUtility.getBKDRKey(idBuffer)));
				docs.add(doc);
				if (innerCount == fetchSize) {
					solrServer.add(docs);
					docs.clear();
					innerCount = 0;
				}
			}
			if (innerCount != 0) {
				solrServer.add(docs);
			}
			if (count > 0)
				solrServer.commit();
		} catch (Exception ex) {
			log.error("添加Solr数据失败:" + tableName, ex);
			lastUpdateTime = 0;
			return 0;
		} finally {
			if (resultSet != null) {
				try {
					resultSet.close();
				} catch (SQLException e) {
				}
				resultSet = null;
			}
			if (statement != null) {
				try {
					statement.close();
				} catch (SQLException e) {
				}
				statement = null;
			}
			if (conn != null) {
				try {
					conn.close();
				} catch (SQLException e) {
				}
			}
		}
		return count;
	}

	private int initCategoryData(ResultSetMetaData rsm, String dbName) {
		int value = -1;
		try {
			int numColumns = rsm.getColumnCount();
			String columnName = null;
			for (int i = 1; i <= numColumns; i++) {
				columnName = rsm.getColumnLabel(i);
				if (columnName.equalsIgnoreCase("category")) {
					value = i;
					break;
				}
			}
			if (value < 0) {
				return value;
			}
			categoryDataMap.clear();
			Connection conn = null;
			ResultSet resultSet = null;
			PreparedStatement statement = null;
			try {
				conn = TqlGlobal.getTqlMaster().getPhysicalPool(dbName).getConnection();
				statement = conn.prepareStatement("select id,name from t_pm_product_category");
				resultSet = statement.executeQuery();
				while (resultSet.next()) {
					categoryDataMap.put(resultSet.getLong(1), resultSet.getString(2));
				}
			} catch (Exception ex) {
				log.error("初始化Category数据失败:" + dbName, ex);
				return 0;
			} finally {
				if (resultSet != null) {
					try {
						resultSet.close();
					} catch (SQLException e) {
					}
					resultSet = null;
				}
				if (statement != null) {
					try {
						statement.close();
					} catch (SQLException e) {
					}
					statement = null;
				}
				if (conn != null) {
					try {
						conn.close();
					} catch (SQLException e) {
					}
				}
			}

		} catch (SQLException e) {
		}
		return value;
	}

	/**
	 * 检查查询结果字段，将Solr中没有的字段添加到Solr中
	 * 
	 * @param rsm
	 *            查询结果
	 * @param tableName
	 *            表名
	 * @param copyFields
	 * @return 添加字段名
	 * @throws SQLException
	 */
	private String[] checkSolrFields(ResultSetMetaData rsm, String tableName, String copyFields) throws SQLException {
		StringTokenizer token = new StringTokenizer(copyFields, ", ");
		HashSet<String> copyFieldsSet = new HashSet<String>();
		while (token.hasMoreElements()) {
			copyFieldsSet.add(token.nextToken());
		}
		int numColumns = rsm.getColumnCount();
		String[] colNames = new String[numColumns + 1];
		HashMap<String, String> existFields = getAllSchemaFields();
		HashSet<String> schemaCopyFields = getAllSchemaCopyFields();
		ArrayList<String> newFieldsInfo = new ArrayList<String>();
		ArrayList<String> newCopyFieldsInfo = new ArrayList<String>();
		for (int i = 1; i < (numColumns + 1); i++) {
			colNames[i] = rsm.getColumnName(i);
			if (colNames[i] != null) {
				colNames[i] = toSolrFieldName(tableName, colNames[i]);
				if (copyFieldsSet.contains(toDbFieldName(tableName, colNames[i]))
						&& !schemaCopyFields.contains(colNames[i])) {
					newCopyFieldsInfo.add(colNames[i]);
				}
				if (!existFields.containsKey(colNames[i])) {
					newFieldsInfo.add(colNames[i]);
					String type;
					switch (rsm.getColumnType(i)) {
					case Types.DATE: {
						type = "date";
						break;
					}
					case Types.TIMESTAMP: {
						type = "date";
						break;
					}
					case Types.BIGINT: {
						type = "long";
						break;
					}
					case Types.INTEGER: {
						type = "int";
						break;
					}
					case Types.FLOAT: {
						type = "float";
						break;
					}
					case Types.DOUBLE: {
						type = "double";
						break;
					}
					case Types.BOOLEAN: {
						type = "boolean";
						break;
					}
					default: {
						type = "textComplex";
					}
					}
					newFieldsInfo.add(type);
				}
			}

		}
		if (!existFields.containsKey("table_name")) {
			newFieldsInfo.add("table_name");
			newFieldsInfo.add("string");
		}
		if (!existFields.containsKey("loadtime")) {
			newFieldsInfo.add("loadtime");
			newFieldsInfo.add("date");
		}
		if (newFieldsInfo.size() > 0) {
			addSolrFields(newFieldsInfo);
		}
		if (newCopyFieldsInfo.size() > 0) {
			addSolrCopyFields(newCopyFieldsInfo);
		}
		return colNames;
	}

	/**
	 * 获取solr已有的字段名
	 * 
	 * @return
	 * @throws HttpException
	 * @throws IOException
	 */
	private HashMap<String, String> getAllSchemaFields() {
		CloseableHttpClient httpclient = HttpClients.createDefault();
		HashMap<String, String> fieldnames = new HashMap<String, String>();
		HttpGet getMethod = null;
		CloseableHttpResponse response = null;
		try {
			getMethod = new HttpGet(getConfigStringValue(config, "//listFieldsUrl"));
			response = httpclient.execute(getMethod);
			String jsonString = EntityUtils.toString(response.getEntity(), "UTF-8");
			JSONObject jsonObject = JSONObject.fromObject(jsonString);
			JSONArray o = (JSONArray) jsonObject.get("fields");
			for (int i = o.size(); --i >= 0;) {
				fieldnames.put(((JSONObject) o.get(i)).getString("name"), ((JSONObject) o.get(i)).getString("type"));
			}
		} catch (Exception ex) {
		} finally {
			if (response != null) {
				try {
					response.close();
				} catch (IOException e) {
				}
			}
			try {
				httpclient.close();
			} catch (IOException e) {
			}
		}
		return fieldnames;
	}

	/**
	 * 获取solr已有的Copy字段名
	 * 
	 * @return
	 * @throws HttpException
	 * @throws IOException
	 */
	private HashSet<String> getAllSchemaCopyFields() {
		CloseableHttpClient httpclient = HttpClients.createDefault();
		HashSet<String> fieldnames = new HashSet<String>();
		HttpGet getMethod = null;
		CloseableHttpResponse response = null;
		try {
			getMethod = new HttpGet(getConfigStringValue(config, "//listCopyFieldsUrl"));
			response = httpclient.execute(getMethod);
			String jsonString = EntityUtils.toString(response.getEntity(), "UTF-8");
			JSONObject jsonObject = JSONObject.fromObject(jsonString);
			JSONArray o = (JSONArray) jsonObject.get("copyFields");
			for (int i = o.size(); --i >= 0;) {
				fieldnames.add(((JSONObject) o.get(i)).getString("source"));
			}
		} catch (Exception ex) {

		} finally {
			if (response != null) {
				try {
					response.close();
				} catch (IOException e) {
				}
			}
			try {
				httpclient.close();
			} catch (IOException e) {
			}
		}
		return fieldnames;
	}

	/**
	 * 将字段更新json发送到solr
	 * 
	 * @throws HttpException
	 * @throws IOException
	 */
	private void addSolrFields(ArrayList<String> fieldInfoList) {
		CloseableHttpClient httpclient = HttpClients.createDefault();
		HttpPost httpPost = null;
		CloseableHttpResponse response = null;
		try {
			int size = fieldInfoList.size() / 2;
			StringBuffer fieldsBuffer = new StringBuffer();
			fieldsBuffer.append("[");
			for (int i = 0; i < size; i++) {
				fieldsBuffer.append("{");
				fieldsBuffer.append("\"name\":\"").append(fieldInfoList.get(2 * i)).append("\",");
				fieldsBuffer.append("\"type\":\"").append(fieldInfoList.get(2 * i + 1)).append("\",");
				fieldsBuffer.append("\"stored\":\"true\"");
				fieldsBuffer.append("}");
				if (i < size - 1)
					fieldsBuffer.append(",");
			}
			fieldsBuffer.append("]");
			httpPost = new HttpPost(getConfigStringValue(config, "//addFieldsUrl"));
			StringEntity entity = new StringEntity(fieldsBuffer.toString(), "UTF-8");
			entity.setContentType("application/json");
			httpPost.setEntity(entity);

			response = httpclient.execute(httpPost);
		} catch (Exception ex) {
			log.error("添加Solr字段失败", ex);
		} finally {
			if (response != null) {
				try {
					response.close();
				} catch (IOException e) {
				}
			}
			try {
				httpclient.close();
			} catch (IOException e) {
			}
		}
	}

	/**
	 * 将copy字段json发送到solr 默认的dest 是text 字段
	 * 
	 * @throws HttpException
	 * @throws IOException
	 */
	private void addSolrCopyFields(ArrayList<String> fieldInfoList) {
		CloseableHttpClient httpclient = HttpClients.createDefault();
		HttpPost httpPost = null;
		CloseableHttpResponse response = null;
		try {
			int size = fieldInfoList.size();
			StringBuffer fieldsBuffer = new StringBuffer();
			// {"source":"sourceField","dest":["target1",...]}
			fieldsBuffer.append("[");
			for (int i = 0; i < size; i++) {
				fieldsBuffer.append("{");
				fieldsBuffer.append("\"source\":\"").append(fieldInfoList.get(i)).append("\",");
				fieldsBuffer.append("\"dest\":[\"text\"]}");
				if (i < size - 1)
					fieldsBuffer.append(",");
			}
			fieldsBuffer.append("]");
			httpPost = new HttpPost(getConfigStringValue(config, "//addCopyFieldsUrl"));
			StringEntity entity = new StringEntity(fieldsBuffer.toString(), "UTF-8");
			entity.setContentType("application/json");
			httpPost.setEntity(entity);

			response = httpclient.execute(httpPost);
		} catch (Exception ex) {
			log.error("添加Solr copy字段失败", ex);
		} finally {
			if (response != null) {
				try {
					response.close();
				} catch (IOException e) {
				}
			}
			try {
				httpclient.close();
			} catch (IOException e) {
			}
		}
	}

	public void query(EngineContext context, TNode tNode) throws Exception {
		try {
			String tbname = tNode.getAttribute("searchTable").getValue();
			String dbname = tNode.getAttribute("dbName").getValue();

			String searchCols = tNode.getAttribute("searchCols").getValue();
			StringBuilder where = new StringBuilder("table_name:"
					+ String.format("%s_%s AND %s_store_id:", dbname, tbname, tbname) + context.get("?storeid"));
			StringBuilder where0 = new StringBuilder();
			// HashMap<String, String> fields = getAllSchemaFields();
			for (String s : searchCols.split(";")) {
				if (context.get(String.format("?%s", s)) == null)
					continue;
				String v = context.get(String.format("?%s", s));
				// String type = fields.get(toSolrFieldName(tbname, s));
				// if (type.equals("string") || type.indexOf("text") > -1)
				// v = "*" + v + "*";
				if (where0.length() > 0) {
					where0.append(" OR ");
				}
				where0.append(s).append(":").append(v);
			}
			if (where0.length() != 0) {
				// where += " AND (" + where0.toString().replaceFirst(" OR ",
				// "") + ")";
				where.append(" AND (");
				String temp = where0.toString().trim();
				String[] values = StringUtils.split(temp, ": ");
				int count = 0;
				String text = values[0];
				for (int i = 1; i < values.length; i++) {
					count = 0;
					if (i > 1) {
						where.append(" OR ");
					}
					where.append("(");
					for (char c : values[i].toCharArray()) {
						if (count++ > 0) {
							where.append(" AND ");
						}
						where.append(text).append(":").append(c);
					}
					where.append(") ");
				}
				where.append(")");
			}
			String orderby = null;
			if (tNode.getAttribute("orderby") != null) {
				orderby = tNode.getAttribute("orderby").getValue();
			}
			String curpage = context.get("?page");
			String pageSize = context.get("?pagesize");
			String returncols = "id";
			SolrDocumentList solrlist = querySolr(tbname, where.toString(), orderby,
					curpage != null ? Integer.parseInt(curpage) : null, pageSize != null ? Integer.parseInt(pageSize)
							: null, returncols.split(","));
			Map.Entry<String, Object> entry;
			StringBuilder sb = new StringBuilder();
			for (SolrDocument solrdoc : solrlist) {
				for (Iterator<Map.Entry<String, Object>> ite = solrdoc.iterator(); ite.hasNext();) {
					entry = ite.next();
					sb.append("," + entry.getValue());
				}
			}

			TNode[] funcNodes = tNode.getChildren();
			TNode outputNode = null;
			for (TNode tFunction : funcNodes) {
				String functionName = tFunction.getNodeName();
				if (functionName.equals("output")) {
					outputNode = tFunction;
				}
			}

			String returnField = outputNode.getAttribute("result").getValue();
			// tQuery node 不知道该去哪个节点获取resultCount配置的值，所以使用固定值@recordcount代替
			// String recordcount =
			// outputNode.getAttributes().getNamedItem("resultCount").getNodeValue();
			if (returnField == null) {
				return;
			}
			if (solrlist.getNumFound() > 0) {
				context.put(returnField, sb.toString().replaceFirst(",", ""));
			} else {
				context.put(returnField, "-1");
			}
			context.put("@recordcount", String.valueOf(solrlist.getNumFound()));
		} finally {
		}
	}

	/**
	 * 查询
	 * 
	 * @param tbname
	 *            表名
	 * @param where
	 *            查询条件
	 * @param orderby
	 *            排序
	 * @param curpage
	 *            当前页
	 * @param pageSize
	 *            每页返回结果数
	 * @param returnFields
	 *            要返回的字段
	 * @return
	 * @throws SolrServerException
	 */
	private SolrDocumentList querySolr(String tbname, String where, String orderby, Integer curpage, Integer pageSize,
			String... returnFields) throws SolrServerException {
		if (curpage == null)
			curpage = 1;
		if (pageSize == null)
			pageSize = Integer.MAX_VALUE;
		SolrQuery query = new SolrQuery();
		query.set("start", (curpage - 1) * pageSize);
		query.set("rows", pageSize);
		if (where != null) {
			/*
			 * Pattern pat = Pattern.compile("[\\w]+\\s*:\\s*[^\\s]+"); Matcher
			 * s = pat.matcher(where); int ind = 0; StringBuilder sb = new
			 * StringBuilder(); while (s.find()) { String group = s.group();
			 * sb.append(where.substring(ind, s.start())); String[] atts =
			 * group.split(":"); sb.append(group.replaceFirst(atts[0].trim(),
			 * toSolrFieldName(tbname, atts[0].trim()))); ind = s.end(); } if
			 * (ind != where.length()) sb.append(where.substring(ind));
			 */

			query.setQuery(where);
		} else
			query.setQuery("table_name:" + tbname + " AND *:*");
		if (returnFields != null) {
			for (String fieldname : returnFields)
				query.addField(toSolrFieldName(tbname, fieldname));
		}
		// 转换order
		if (orderby != null) {
			for (String orderstr : orderby.split(";")) {
				String field = orderstr.split(",")[0];
				String order = orderstr.split(",")[1];
				SolrQuery.ORDER rorder = order.toLowerCase().equals("asc") ? SolrQuery.ORDER.asc : SolrQuery.ORDER.desc;
				query.addSort(toSolrFieldName(tbname, field), rorder);
			}
		}
		QueryResponse queryResponse = solrServer.query(query);
		SolrDocumentList sdl = (SolrDocumentList) queryResponse.getResponse().get("response");
		Map.Entry<String, Object> entry;
		for (SolrDocument solrdoc : sdl) {
			SolrDocument nsolrdoc = new SolrDocument();
			nsolrdoc.putAll(solrdoc);
			solrdoc.clear();
			for (Iterator<Map.Entry<String, Object>> ite = nsolrdoc.iterator(); ite.hasNext();) {
				entry = ite.next();
				solrdoc.put(toDbFieldName(tbname, entry.getKey()), entry.getValue());
			}
		}
		return sdl;
	}

	/**
	 * 将solr中存储的字段名转为数据库字段名
	 * 
	 * @param tableName
	 *            数据库表名
	 * @param solrFdName
	 *            solr字段名
	 * @return
	 */
	private String toDbFieldName(String tableName, String solrFdName) {
		if (!(solrFdName.equals("table_name") || solrFdName.equals("text"))) {
			return solrFdName.replaceFirst(tableName + "_", "");
		}
		return solrFdName;
	}

	/**
	 * 将数据库字段名转为Solr中存储的字段名
	 * 
	 * @param tableName
	 *            数据库表名
	 * @param dbFieldName
	 *            数据库表字段名
	 * @return
	 */
	private String toSolrFieldName(String tableName, String dbFieldName) {
		if (!(dbFieldName.equals("table_name") || dbFieldName.equals("text"))) {
			return tableName + "_" + dbFieldName.toLowerCase();
		}
		return dbFieldName;
	}

	/**
	 * 获取上次数据同步时间戳
	 * 
	 * @param tbname
	 * @return
	 */
	private long getTimestamp(String tableName) {
		Properties prop = new Properties();
		File defineFile = new File(System.getProperty(AppConfiguration.getWebRootName()), "WEB-INF/data/solrsyn.tmp");
		if (!defineFile.exists())
			return 0;
		FileInputStream fis = null;
		try {
			fis = new FileInputStream(defineFile);
			prop.load(fis);
			Long stamp = Long.parseLong(prop.getProperty(tableName + "_SolrSynJob_stamp"));
			return stamp;
		} catch (Exception e) {
		} finally {
			if (fis != null)
				try {
					fis.close();
				} catch (IOException e1) {
				}
		}
		return 0;
	}

	/**
	 * 保存数据同步时间戳
	 * 
	 * @param tbname
	 * @param stamp
	 */
	private void saveTimestamp(String tableName, long stamp) {
		Properties prop = new Properties();
		File defineFile = new File(System.getProperty(AppConfiguration.getWebRootName()), "WEB-INF/data/solrsyn.tmp");
		FileInputStream fis = null;
		try {
			FileUtils.forceMkdir(defineFile.getParentFile());
			fis = new FileInputStream(defineFile);
			prop.load(fis);
		} catch (IOException e) {
		} finally {
			if (fis != null)
				try {
					fis.close();
				} catch (IOException e1) {
				}
		}
		prop.setProperty(tableName + "_SolrSynJob_stamp", String.valueOf(stamp));
		FileOutputStream fos = null;
		try {
			fos = new FileOutputStream(defineFile);
			prop.store(fos, "solrsyn");
		} catch (Exception e) {
		} finally {
			if (fos != null)
				try {
					fos.close();
				} catch (IOException e1) {
				}
		}
	}

	public static void main(String[] a) throws SolrServerException, IOException, Exception {
		// SolrProcessor processor = new SolrProcessor();
		// processor.query("product",null,"id asc",3,2);
		// processor.clearSolr(null);
		// System.out.println(SolrProcessor.class.getName());
	}

}
